
open Chipmunk.Low_level

let getUniq = 
	let counter = ref 0 in
	let func () = 
		let () = incr counter in
		!counter
	in func

type id_type = int
module IdMap = Map.Make(struct type t = id_type let compare = compare end)
module IntMap = Map.Make(struct type t = int let compare = compare end)

module Point = struct
	type t = cpVect
	let to_string point1 = "(" ^ string_of_float point1.cp_x ^ "," ^ string_of_float point1.cp_y ^ ")"
	let zero = cpvzero
	let (+) point1 point2 = cpvadd point1 point2
	(* unary minus *)
	let (~-) point1 = cpvneg point1
	let (-) point1 point2 = cpvsub point1 point2
	(* scalar multiplication *)
	let ( * ) point1 scalar = cpvmult point1 scalar
	(* dot product *)
	let ( <.> ) point1 point2 = cpvdot point1 point2
	(* cross product *)
	let ( <*> ) point1 point2 = cpvcross point1 point2
	let norm point1 = cpvlength point1
end

module Data = struct
	type t = Float of float | String of string | List of t list
	exception BadParse of string
	let rec show data = match data with
		| Float  x -> string_of_float x
		| String s -> "\"" ^ String.escaped s ^ "\""
		| List   l -> List.fold_left (fun acc elem -> acc ^ " " ^ show elem) "(" l ^ " )"
	let read string = 
		(* read from string in [start, stop), 
		 * returns (data, start+bytes_read). *)
		let rec read string start stop =
				if start >= stop then raise (BadParse "Unexpected EOF")
				else try 
						read_float string start stop
					with BadParse s1 -> try
						read_string string start stop
					with BadParse s2 -> try
						read_list string start stop
					with BadParse s3 -> 
						raise (BadParse (s1 ^ "\n" ^ s2 ^ "\n" ^ s3 ^ "\n"))
			and read_float string start stop = 
				try Scanf.sscanf (Str.string_after string start) 
						" %f%n" (fun x n -> (Float  x, start + n))
				with Scanf.Scan_failure s -> raise (BadParse s)
			and read_string string start stop = 
				try Scanf.sscanf (Str.string_after string start)
						" %S%n" (fun s n -> (String s, start + n))
				with Scanf.Scan_failure s -> raise (BadParse s)
			and read_list string start stop = 
				let continuation n = 
					let (ds, start') = read_list_interior string (start + n) stop in
					(List ds, start')
				in try Scanf.sscanf (Str.string_after string start) " (%n" continuation
				with Scanf.Scan_failure s -> raise (BadParse s)
			and read_list_interior string start stop = 
				if start >= stop then raise (BadParse "Unexpected EOF")
				else try
						let (elem, start') = read string start stop in
						let (tail, start'') = read_list_interior string start' stop in
						(elem :: tail, start'')
					with BadParse s1 -> try
						read_list_end string start stop
					with BadParse s2 -> raise (BadParse (s1 ^ "\n" ^ s2 ^ "\n"))
			and read_list_end string start stop = 
				if start >= stop then raise (BadParse "Unexpected EOF")
				else try Scanf.sscanf (Str.string_after string start) 
							" )%n" (fun n -> ([], start+n))
					with Scanf.Scan_failure s -> raise (BadParse s)
		in 
		let strlen = String.length string in
		let (data, start') = read string 0 strlen in
		let () = if start' < strlen then 
			try Scanf.sscanf (Str.string_after string start') " %!" () 
			with Scanf.Scan_failure s -> raise (BadParse s)
		in data
				
	let of_float  x = Float  x
	let of_string s = String s
	let of_list   l = List   l
	let to_float  d = match d with Float  x -> x | _ -> failwith ("wrong data: " ^ show d)
	let to_string d = match d with String s -> s | _ -> failwith ("wrong data: " ^ show d)
	let to_list   d = match d with List   l -> l | _ -> failwith ("wrong data: " ^ show d)

	let marshal   data   = Marshal.to_string data [Marshal.No_sharing]
	let unmarshal string = (Marshal.from_string string 0 : t)
end

type game_engine_api = Data.t -> Data.t

